﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Windows.Forms;
using System.Xml.Serialization;

namespace RSSReader
{
    class SeriesEpisode
    {
        public string Title { get; set; }
        public int Season { get; set; }
        public int Episode { get; set; }

        public SeriesEpisode(string title, int season, int episode)
        {
            Title = title;
            Season = season;
            Episode = episode;
        }
    }

    class Program
    {
        private const string FEEDS_FILENAME = "RssFeeds.xml";
        private const string TITLES_FILENAME = "RssTitles.xml";
        private const string ITEMS_FILENAME = "RssItems.xml";
        private const string IGNORE_LIST_FILENAME = "RssIgnoreList.xml";
        private const string DROPBOX_DATA_FILENAME = "DropboxData.xml";
        
        private static RSSFeeds m_rssFeeds;
        private static RSSTitlesToMatch m_rssTitles;
        private static RSSDashboard m_gui;
        private static RSSItems m_allRssItems;
        private static RSSIgnoreList m_ignoreList;
        private static DropboxData m_dropboxData;

        private static Timer timer = new Timer();

        static void Main(string[] args)
        {
            if (args.Length > 0)
            {
                timer.Interval = 6000;
            }
            else
            {
                timer.Interval = 60000;
            }
            timer.Tick += timerCallback;

            timer.Enabled = true;
            m_gui = new RSSDashboard();

            m_rssTitles = new RSSTitlesToMatch();
            ReadRssTitles();

            m_rssFeeds = new RSSFeeds();
            ReadRssFeeds();

            m_allRssItems = new RSSItems();
            ReadRssItems();

            m_ignoreList = new RSSIgnoreList();
            ReadIgnoreList();

            m_dropboxData = new DropboxData();
            ReadDropboxData();

            m_gui.SelectLastItem();

            m_gui.ShowDialog();
        }

        private static void ReadRssTitles()
        {
            XmlSerializer serializer = new XmlSerializer(typeof(RSSTitlesToMatch));
            if (!File.Exists(TITLES_FILENAME))
                return;

            FileStream fs = new FileStream(TITLES_FILENAME, FileMode.Open);
            m_rssTitles = (RSSTitlesToMatch)serializer.Deserialize(fs);
            fs.Close();

            foreach (RSSTitleToMatch title in m_rssTitles)
            {
                m_gui.AddTitleRow(title.Title, title.IsMovie, title.Quality);
            }            
        }

        private static void ReadRssFeeds()
        {
            XmlSerializer serializer = new XmlSerializer(typeof(RSSFeeds));
            if (!File.Exists(FEEDS_FILENAME))
                return;

            FileStream fs = new FileStream(FEEDS_FILENAME, FileMode.Open);
            m_rssFeeds = (RSSFeeds)serializer.Deserialize(fs);
            fs.Close();

            foreach (RSSFeed feed in m_rssFeeds.Feeds)
            {
                m_gui.AddFeedRow(feed.RSSName, feed.RSSUrl);
            }
        }

        private static void ReadIgnoreList()
        {
            XmlSerializer serializer = new XmlSerializer(typeof(RSSIgnoreList));
            if (!File.Exists(IGNORE_LIST_FILENAME))
                return;

            FileStream fs = new FileStream(IGNORE_LIST_FILENAME, FileMode.Open);
            m_ignoreList = (RSSIgnoreList)serializer.Deserialize(fs);
            fs.Close();

            m_gui.SetIgnoreList(m_ignoreList.ToString());
        }

        private static void ReadDropboxData()
        {
            XmlSerializer serializer = new XmlSerializer(typeof(DropboxData));
            if (!File.Exists(DROPBOX_DATA_FILENAME))
                return;

            FileStream fs = new FileStream(DROPBOX_DATA_FILENAME, FileMode.Open);
            m_dropboxData = (DropboxData)serializer.Deserialize(fs);
            fs.Close();

            m_gui.SetDropboxFilename(m_dropboxData.DropboxFilename);
        }

        private static void ReadRssItems()
        {
            XmlSerializer serializer = new XmlSerializer(typeof(RSSItems));
            if (!File.Exists(ITEMS_FILENAME))
                return;

            FileStream fs = new FileStream(ITEMS_FILENAME, FileMode.Open);
            m_allRssItems = (RSSItems)serializer.Deserialize(fs);
            fs.Close();

            bool found = false;
            foreach (RSSItem item in m_allRssItems.Items)
            {
                if (item.Title.Contains("/") || item.Title.Contains("("))
                {
                    found = true;
                    break;
                }
            }
            if (found)
            {
                CleanRssItemTitles();
            }
            
            foreach (RSSItem item in m_allRssItems.Items)
            {
                AddrssItem(item);
            }
        }

        private static void CleanRssItemTitles()
        {
            foreach (RSSItem item in m_allRssItems.Items)
            {
                if (item.IsSeries)
                {
                    int titleEndPos = -1;
                    SeriesEpisode seriesEpisode = Utils.GetSeriesEpisodeUsingSXEPattern(item.Title, out titleEndPos);
                    if (seriesEpisode == null)
                    {
                        seriesEpisode = Utils.GetSeriesEpisodeUsingSeasonEpisodePattern(item.Title, out titleEndPos);
                    }
                    if (seriesEpisode == null)
                    {
                        seriesEpisode = Utils.GetSeriesEpisodeUsingSEPattern(item.Title, out titleEndPos);
                    }

                    if (seriesEpisode != null)
                    {
                        item.Title = item.Title.Substring(0, titleEndPos);
                        item.Title = Utils.CleanRssItemTitle(item.Title);
                    }
                }
                else
                {
                    item.Title = Utils.CleanRssItemTitle(item.Title);
                }

                if (item.Found)
                {
                    item.State = AddState.FoundAndAdded;
                }
                else
                {
                    item.State = AddState.NotFound;
                }
            }

            UpdateRssItemsFile();
        }

        public static void RunTimerCallback()
        {
            timerCallback(timer, null);
        }

        private static void timerCallback(object sender, EventArgs e)
        {
            Timer timer = (Timer) sender;
            timer.Enabled = false;

            try
            {

                // RSS
                //
                foreach (RSSFeed rssFeed in m_rssFeeds.Feeds)
                {
                    RSSItems items = rssFeed.GetNewItems(m_rssTitles, m_allRssItems, m_ignoreList);
                    foreach (RSSItem item in items.Items)
                    {
                        AddrssItem(item);
                    }

                    m_allRssItems.AddItems(items);
                }

                // Dropbox
                //
                if (!string.IsNullOrEmpty(m_dropboxData.DropboxFilename))
                {
                    RSSItems items = m_dropboxData.ProcessDropboxData();
                    foreach (RSSItem item in items.Items)
                    {
                        AddrssItem(item);
                    }

                    m_allRssItems.AddItems(items);
                }

                UpdateRssItemsFile();
                UpdateRssFeedsFile();

            }
            catch (Exception ex)
            {
                //File.AppendAllText("RssReaderLog.txt", "Exception during timer callback " + ex);
            }

            m_gui.SetLastUpdateDateTime(DateTime.Now);
            timer.Enabled = true;
        }

        private static void AddrssItem(RSSItem item)
        {
            m_gui.AddRssItem(item);
        }

        public static void AddRSSFeed(string name, string url)
        {
            m_rssFeeds.Add(new RSSFeed(name, url));
            UpdateRssFeedsFile();
        }

        public static void DeleteRSSFeed(int rowIndex)
        {
            m_rssFeeds.Feeds.RemoveAt(rowIndex);
            UpdateRssFeedsFile();
        }

        public static void DeleteTitle(int rowIndex)
        {
            m_rssTitles.Titles.RemoveAt(rowIndex);
            UpdateRssTitlesFile();
        }

        private static void UpdateRssFeedsFile()
        {
            XmlSerializer serializer = new XmlSerializer(typeof(RSSFeeds));
            TextWriter writer = new StreamWriter(FEEDS_FILENAME);
            serializer.Serialize(writer, m_rssFeeds);
            writer.Close();
        }

        private static void UpdateRssItemsFile()
        {
            XmlSerializer serializer = new XmlSerializer(typeof(RSSItems));
            TextWriter writer = new StreamWriter(ITEMS_FILENAME);
            serializer.Serialize(writer, m_allRssItems);
            writer.Close();            
        }

        private static void UpdateRssIgnoreList()
        {
            XmlSerializer serializer = new XmlSerializer(typeof(RSSIgnoreList));
            TextWriter writer = new StreamWriter(IGNORE_LIST_FILENAME);
            serializer.Serialize(writer, m_ignoreList);
            writer.Close();
        }

        private static void UpdateDropboxData()
        {
            XmlSerializer serializer = new XmlSerializer(typeof(DropboxData));
            TextWriter writer = new StreamWriter(DROPBOX_DATA_FILENAME);
            serializer.Serialize(writer, m_dropboxData);
            writer.Close();
        }

        public static void AddRSSTtitle(string title, bool isMovie, string quality)
        {
            m_rssTitles.Add(new RSSTitleToMatch(title, isMovie, quality));
            UpdateRssTitlesFile();
        }

        private static void UpdateRssTitlesFile()
        {
            XmlSerializer serializer = new XmlSerializer(typeof(RSSTitlesToMatch));
            TextWriter writer = new StreamWriter(TITLES_FILENAME);
            serializer.Serialize(writer, m_rssTitles);
            writer.Close();
        }

        public static void SearchItem(RSSItem item, bool checkExistenceAndAge)
        {
            timer.Enabled = false;

            RSSItems items = new RSSItems();
            List<string> log = new List<string>();
            string titleToMatch = item.Title + (item.IsSeries ? String.Format(" S{0:00}E{1:00}", item.Season, item.Episode) : "");
            RSSFeed.FindTitle(items, log, item.URL, item.PubDate, titleToMatch, m_rssTitles, m_allRssItems, m_ignoreList, checkExistenceAndAge);
            
            foreach (RSSItem newItem in items.Items)
            {
                AddrssItem(newItem);
            }
            m_allRssItems.AddItems(items);
            UpdateRssItemsFile();
            
            m_gui.SetLastUpdateDateTime(DateTime.Now);

            timer.Enabled = true;
        }

        public static void SetIgnoreList(string ignoreList)
        {
            m_ignoreList.SetFromString(ignoreList);
            UpdateRssIgnoreList();
        }

        public static void SetDropboxFilename(string dropboxFilename)
        {
            m_dropboxData.DropboxFilename = dropboxFilename;
            UpdateDropboxData();
        }
    }
}
